package com.xpj.aspect;

import com.xpj.annotation.CacheQuery;
import com.xpj.template.CacheTemplate;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.redisson.api.RBloomFilter;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;

@Slf4j
@Aspect
@Component
public class CacheQueryAspect {

    @Autowired
    private ApplicationContext applicationContext;

    @Autowired
    private CacheTemplate cacheTemplate;

    @Autowired
    private RedissonClient redissonClient;

    @Pointcut("@annotation(com.xpj.annotation.CacheQuery)")
    public void cacheQueryPointcut() {}

    @Around("cacheQueryPointcut() && @annotation(cacheQuery)")
    public Object cacheQueryAround(ProceedingJoinPoint joinPoint, CacheQuery cacheQuery) throws Throwable {

        String cacheKey = CacheAnnotationProcessor.generateCacheKey(joinPoint, cacheQuery);
        if (cacheKey == null) {
            log.warn("缓存键生成失败，method: {}", joinPoint.getSignature());
            return joinPoint.proceed();
        }

        RBloomFilter<String> bloomFilter = getBloomFilter(cacheQuery);

        String rwLockKey = "rw:lock:" + cacheKey;
        RLock rLock = redissonClient.getReadWriteLock(rwLockKey).readLock();
        try {
            boolean b = rLock.tryLock(3, TimeUnit.SECONDS);
            if (!b){
                log.warn("获取读锁失败，key: {}", cacheKey);
            }
            return cacheTemplate.query(cacheKey, cacheQuery.ttl(), () -> {
                try {
                    return joinPoint.proceed();
                } catch (Throwable e) {
                    log.error("执行原方法异常", e);
                    throw new RuntimeException(e);
                }
            }, bloomFilter);
        }finally {
            if (rLock.isHeldByCurrentThread()){
                rLock.unlock();
            }
        }
    }
    private RBloomFilter<String> getBloomFilter(CacheQuery cacheQuery) {
        RBloomFilter<String> bloomFilter = null;
        if (cacheQuery.useBloomFilter()){
            try {
                bloomFilter = (RBloomFilter<String>) applicationContext.getBean(cacheQuery.bloomFilterBean(),
                        RBloomFilter.class);
            } catch (Exception e) {
                log.error("获取布隆过滤器失败，beanName: {}", cacheQuery.bloomFilterBean(), e);
            }
        }
        return bloomFilter;
    }



}
